package service

import (
	"gin-gorm-oj/model"
	"gin-gorm-oj/utils"
	"log"
	"net/http"
	"strconv"
	"strings"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

// GetCategoryList 处理获取分类列表的请求
// @Tags 公共方法
// @Summary 分类列表
// @Param page query int false "页码"  // 查询参数，选填
// @Param size query int false "每页记录数"  // 查询参数，选填
// @Param keyword query string false "关键字"  // 查询参数，选填
// @Success 200 {string} json "{"code":"200","data":""}"
// @Router /category-list [get]
func GetCategoryList(c *gin.Context) {
	// 从查询参数中获取每页记录数和页码
	size, page := utils.GetSizeAndPage(c)
	if size == -1 {
		// 如果分页参数出错，返回
		return
	}

	keyword := c.Query("keyword") // 从查询参数中获取搜索关键字

	// 初始化分类列表
	categoryList := make([]*model.Category, 0)
	var count int64
	// 查询数据库，获取符合条件的分类列表
	err := utils.DB.Model(new(model.Category)).
		Where("name like ?", "%"+keyword+"%").
		Count(&count). // 统计符合条件的分类总数
		Limit(size).   // 设置每页记录数
		Offset(page).  // 设置偏移量
		Find(&categoryList).Error
	if err != nil {
		log.Println("GetCategoryList Error:", err)
		c.JSON(http.StatusOK, gin.H{
			"code": -1,
			"msg":  "获取分类列表失败",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code": 200,
		"data": map[string]interface{}{
			"list":  categoryList,
			"count": count,
		},
	})
}

// GetProblemList
// @Tags 公共方法
// @Summary 问题列表
// @Param page query int false "页码"  // 查询参数，选填
// @Param size query int false "每页记录数"  // 查询参数，选填
// @Param keyword query string false "关键字"  // 查询参数，选填
// @Param category_id query string false "分类id" // 查询参数，选填
// @Success 200 {string} json "{"code":"200","data":""}"
// @Router /problem-list [get]
func GetProblemList(c *gin.Context) {
	// 从查询参数中获取每页记录数和页码
	size, page := utils.GetSizeAndPage(c)
	if size == -1 {
		// 如果分页参数出错，返回
		return
	}

	// 获取查询参数中的关键词和分类标识符
	keyword := c.Query("keyword")
	categoryId := c.Query("category_id")

	// 创建一个切片，用于存储查询到的问题列表
	list := make([]*model.Problem, 0)
	var count int64
	// 获取问题列表并统计总数
	err := utils.GetProblems(keyword, categoryId).Count(&count).Error
	if err != nil {
		log.Println("GetProblemList Count Error:", err)
		return
	}

	// 获取问题列表，进行分页
	err = utils.GetProblems(keyword, categoryId).
		Offset(page).     // 设置偏移量
		Limit(size).      // 设置每页记录数
		Find(&list).Error // 执行查询并将结果赋值给 list
	if err != nil {
		log.Println("Get Problem List Error:", err)
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code": 200,
		"data": map[string]interface{}{
			"list":  list,
			"count": count,
		},
	})
}

// GetSubmitList
// @Tags 公共方法
// @Summary 提交列表
// @Param page query int false "页码"  // 查询参数，选填
// @Param size query int false "每页记录数"  // 查询参数，选填
// @Param problem_id query int false "问题id" // 查询参数，选填
// @Param user_id query int false "用户id" // 查询参数，选填
// @Param status query int false "提交状态" // 查询参数，选填
// @Success 200 {string} json "{"code":"200","data":""}"
// @Router /submit-list [get]
func GetSubmitList(c *gin.Context) {
	// 从查询参数中获取每页记录数和页码
	size, page := utils.GetSizeAndPage(c)
	if size == -1 {
		// 如果分页参数出错，返回
		return
	}

	// 创建一个切片用于存储查询到的提交列表
	list := make([]*model.Submit, 0)

	// 从查询参数中获取问题和用户id
	problemId := c.Query("problem_id")
	userId := c.Query("user_id")
	// 从查询参数中获取提交状态并转换为整数
	status, _ := strconv.Atoi(c.Query("status"))

	// 获取提交列表的查询构建器
	tx := utils.GetSubmits(problemId, userId, status)
	var count int64
	// 执行查询，统计提交总数并进行分页
	err := tx.Count(&count).
		Offset(page). // 设置偏移量
		Limit(size).  // 设置每页记录数
		Find(&list).Error
	if err != nil {
		log.Println("Get Problem List Error:", err)
		c.JSON(http.StatusOK, gin.H{
			"code": -1,
			"msg":  "Get Submit List Error:" + err.Error(),
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code": 200,
		"data": map[string]interface{}{
			"list":  list,
			"count": count,
		},
	})
}

// GetRankList
// @Tags 公共方法
// @Summary 用户排行榜
// @Param page query int false "页码"  // 查询参数，选填
// @Param size query int false "每页记录数"  // 查询参数，选填
// @Success 200 {string} json "{"code":"200","data":""}"
// @Router /rank-list [get]
func GetRankList(c *gin.Context) {
	// 从查询参数中获取每页记录数和页码
	size, page := utils.GetSizeAndPage(c)
	if size == -1 {
		// 如果分页参数出错，返回
		return
	}

	// 创建一个切片用于存储查询到的用户列表
	list := make([]*model.User, 0)
	var count int64
	// 查询用户总数并获取用户排行榜数据，按通过次数降序、提交次数升序排序
	err := utils.DB.Model(new(model.User)).
		Count(&count).                          // 统计用户总数
		Order("pass_num DESC, submit_num ASC"). // 排序规则
		Offset(page).                           // 设置偏移量
		Limit(size).                            // 设置每页记录数
		Find(&list).Error
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": -1,
			"msg":  "Get Rank List Error:" + err.Error(),
		})
		return
	}

	// 遍历用户列表，隐藏邮箱的部分字符
	for _, v := range list {
		mail := strings.Split(v.Mail, "@") // 分割邮箱
		if len(mail) >= 2 {
			// 将邮箱的用户名部分的第一个字符替换为星号
			v.Mail = string(mail[0][0]) + "**@" + mail[1]
		}
	}

	c.JSON(http.StatusOK, gin.H{
		"code": 200,
		"data": map[string]interface{}{
			"list":  list,
			"count": count,
		},
	})
}

// GetProblemDetail
// @Tags 公共方法
// @Summary 获取问题详情
// @Param id query int true "问题id" // 查询参数，必填
// @Success 200 {string} json "{"code":"200","data":""}"
// @Router /problem-detail [get]
func GetProblemDetail(c *gin.Context) {
	// 从查询参数中获取问题id
	id := c.Query("id")

	// 创建一个 Problem 类型的指针，用于存储查询结果
	data := new(model.Problem)

	// 查询问题详情，使用id进行查找，并预加载相关的分类信息
	err := utils.DB.Where("id = ?", id).
		Preload("Category"). // 预加载问题分类
		First(&data).Error   // 获取第一条匹配记录

	if err != nil {
		if err == gorm.ErrRecordNotFound {
			c.JSON(http.StatusOK, gin.H{
				"code": -1,
				"msg":  "问题不存在",
			})
			return
		}
		c.JSON(http.StatusOK, gin.H{
			"code": -1,
			"msg":  "Get Problem Details Error:" + err.Error(),
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code": 200,
		"data": data,
	})
}

// GetUserDetail
// @Tags 公共方法
// @Summary 获取用户详情
// @Param id query int true "用户id" // 查询参数，必填
// @Success 200 {string} json "{"code":"200","data":""}"
// @Router /user-detail [get]
func GetUserDetail(c *gin.Context) {
	// 从查询参数中获取用户id
	id := c.Query("id")

	// 创建一个 User 类型的指针，用于存储查询结果
	data := new(model.User)

	// 查询用户详情，使用id进行查找，排除密码字段
	err := utils.DB.Omit("password").Where("id = ? ", id).First(&data).Error

	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": -1,
			"msg":  "Get User Detail By Id:" + id + " Error:" + err.Error(),
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code": 200,
		"data": data,
	})
}
